`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/11/20 19:52:04
// Design Name: 
// Module Name: rgmii2gmii
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module rgmii2gmii(
    //to phy rgmii
    input   [3:0]   i_rgmii_rxd     ,
    input           i_rgmii_rxctl   ,
    input           i_rgmii_rxc     ,
    output   [3:0]  o_rgmii_txd     ,
    output          o_rgmii_txctl   ,
    output          o_rgmii_txc     ,

    //to clock cross 
    output          o_gmii_clk     ,
    output  [7:0]   o_gmii_rxdata   ,
    output          o_gmii_rxvalid  ,
    input   [7:0]   i_gmii_txdata   ,
    input           i_gmii_txvalid  
);

    logic   rgmii_rxc_bufio;
    logic   rgmii_rxc_bufg;
    logic   rgmii_rxctl;
    logic   [3:0]rgmii_rxd;
    logic   [1:0]rx_ctl;
    logic   [7:0]rx_data;
    logic   or_gmii_rxvalid;
    logic   [7:0]or_gmii_rxdata;

    logic   [7:0]ri_gmii_txdata;
    logic   ri_gmii_txvalid;


    assign o_gmii_clk = rgmii_rxc_bufg;
    assign o_gmii_rxdata = or_gmii_rxdata;
    assign o_gmii_rxvalid = or_gmii_rxvalid;

    assign o_rgmii_txc = rgmii_rxc_bufg;

    always_ff @(posedge rgmii_rxc_bufg) begin
        or_gmii_rxvalid <= rx_ctl[0] & rx_ctl[1];
        or_gmii_rxdata <= rx_data;
    end

    always_ff @(posedge rgmii_rxc_bufg) begin
        ri_gmii_txvalid <= i_gmii_txvalid;
        ri_gmii_txdata <= i_gmii_txdata;
    end


    //clock

    BUFIO BUFIO_inst (
        .O              (rgmii_rxc_bufio        ), // 1-bit output: Clock output (connect to I/O clock loads).
        .I              (i_rgmii_rxc            )  // 1-bit input: Clock input (connect to an IBUF or BUFMR).
    );

    BUFG BUFG_inst (
        .O              (rgmii_rxc_bufg         ), // 1-bit output: Clock output
        .I              (i_rgmii_rxc            )  // 1-bit input: Clock input
    );


    //ddr to sdr use clk from BUFIO to improve performance
    //rx ctrl
    IBUF #(
        .IBUF_LOW_PWR   ("TRUE"             ),  // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
        .IOSTANDARD     ("DEFAULT"          )  // Specify the input I/O standard
    )   
    IBUF_u0 (   
        .O              (rgmii_rxctl                ),     // Buffer output
        .I              (i_rgmii_rxctl            )      // Buffer input (connect directly to top-level port)
    );

    IDDR #(
        .DDR_CLK_EDGE   ("SAME_EDGE_PIPELINED"  ), // "OPPOSITE_EDGE", "SAME_EDGE" 
                                            //    or "SAME_EDGE_PIPELINED" 
        .INIT_Q1        (1'b0               ), // Initial value of Q1: 1'b0 or 1'b1
        .INIT_Q2        (1'b0               ), // Initial value of Q2: 1'b0 or 1'b1
        .SRTYPE         ("SYNC"             ) // Set/Reset type: "SYNC" or "ASYNC" 
    ) 
    IDDR_u0 (
        .Q1             (rx_ctl[0]         ), // 1-bit output for positive edge of clock
        .Q2             (rx_ctl[1]         ), // 1-bit output for negative edge of clock
        .C              (rgmii_rxc_bufio        ),   // 1-bit clock input
        .CE             (1                  ), // 1-bit clock enable input
        .D              (rgmii_rxctl       ),   // 1-bit DDR data input
        .R              (0                  ),   // 1-bit reset
        .S              (0                  )    // 1-bit set
    );
    //rx data
    generate
        for(genvar i = 0; i < 4 ; i = i + 1) begin
            IBUF #(
                .IBUF_LOW_PWR   ("TRUE"         ),  // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
                .IOSTANDARD     ("DEFAULT"      )  // Specify the input I/O standard
            ) 
            IBUF_ux (
                .O              (rgmii_rxd[i]  ),     // Buffer output
                .I              (i_rgmii_rxd[i]       )      // Buffer input (connect directly to top-level port)
            );

            IDDR #(
                .DDR_CLK_EDGE   ("SAME_EDGE_PIPELINED"  ), // "OPPOSITE_EDGE", "SAME_EDGE" 
                                                    //    or "SAME_EDGE_PIPELINED" 
                .INIT_Q1        (1'b0               ), // Initial value of Q1: 1'b0 or 1'b1
                .INIT_Q2        (1'b0               ), // Initial value of Q2: 1'b0 or 1'b1
                .SRTYPE         ("SYNC"             ) // Set/Reset type: "SYNC" or "ASYNC" 
            ) 
            IDDR_ux (
                .Q1             (rx_data[i]           ), // 1-bit output for positive edge of clock
                .Q2             (rx_data[i + 4]       ), // 1-bit output for negative edge of clock
                .C              (rgmii_rxc_bufio        ),   // 1-bit clock input
                .CE             (1                  ), // 1-bit clock enable input
                .D              (rgmii_rxd[i]      ),   // 1-bit DDR data input
                .R              (0                  ),   // 1-bit reset
                .S              (0                  )    // 1-bit set
            );
        end
    endgenerate


    //output sdr to ddr
    //tx data
    generate
        for(genvar j = 0;j < 4 ; j = j + 1)
        begin
            ODDR #(
                .DDR_CLK_EDGE   ("SAME_EDGE"        ), // "OPPOSITE_EDGE" or "SAME_EDGE" 
                .INIT           (1'b0               ),    // Initial value of Q: 1'b0 or 1'b1
                .SRTYPE         ("SYNC"             ) // Set/Reset type: "SYNC" or "ASYNC" 
            )
            ODDR_ux 
            (
                .Q              (o_rgmii_txd[j]           ),   // 1-bit DDR output
                .C              (rgmii_rxc_bufg              ),   // 1-bit clock input
                .CE             (1                  ), // 1-bit clock enable inputs
                .D1             (i_gmii_txdata[j]  ), // 1-bit data input (positive edge)
                .D2             (i_gmii_txdata[j + 4]), // 1-bit data input (negative edge)
                .R              (0                  ),   // 1-bit reset
                .S              (0                  )    // 1-bit set
            );
        end
    endgenerate

    //tx ctrl
    ODDR #(
        .DDR_CLK_EDGE           ("SAME_EDGE"        ), // "OPPOSITE_EDGE" or "SAME_EDGE" 
        .INIT                   (1'b0               ),    // Initial value of Q: 1'b0 or 1'b1
        .SRTYPE                 ("SYNC"             ) // Set/Reset type: "SYNC" or "ASYNC" 
    )       
    ODDR_u0         
    (       
        .Q                      (o_rgmii_txctl            ),   // 1-bit DDR output
        .C                      (rgmii_rxc_bufg              ),   // 1-bit clock input
        .CE                     (1                  ), // 1-bit clock enable input
        .D1                     (i_gmii_txvalid    ), // 1-bit data input (positive edge)
        .D2                     (i_gmii_txvalid    ), // 1-bit data input (negative edge)
        .R                      (0                  ),   // 1-bit reset
        .S                      (0                  )    // 1-bit set
    );



endmodule
